<?php declare(strict_types=1);

namespace App\Bac\Model\RBAC;

use App\Constants\Business;
use App\Exception\BusinessException;
use App\Helper\JwtHelper;
use App\Helper\RespHelper;
use DbModels\RBAC\RoleAdmin;
use Hyperf\Context\Context;
use Hyperf\DbConnection\Db;
use App\Bac\Handler\RBAC\MenuHandler;

class Admin extends \DbModels\RBAC\Admin
{

    public const STATE_DELETE = 0;// 删除
    public const STATE_NORMAL = 1;// 正常
    public const STATE_DISABLE = 2;// 禁用

    public bool $timestamps = false;

    /** @var string 设置密码 hash 算法 */
    protected const PASSWORD_ALG = PASSWORD_BCRYPT;

    public static function getRbacCacheKey(int $id): string
    {
        return Business::CACHE_RBAC_PREFIX . $id;
    }

    public function clearRbacCache(int $id = null): void
    {
        getRedis()->del(self::getRbacCacheKey($id ?: $this->id));
    }

    /**
     * 获取当前登录的用户对象
     * @return Admin|null
     */
    public static function getCurAdmin(): ?Admin
    {
        return Context::get(Business::CONTEXT_KEY_AUTH_ADMIN);
    }

    /**
     * 设置用户密码
     * @param string $password
     */
    public function setPassword(string $password): void
    {
        $this->password = password_hash($password, self::PASSWORD_ALG);
    }

    /**
     * 验证密码是否正确
     * @param string $password
     * @return bool
     */
    public function validatePassword(string $password): bool
    {
        return password_verify($password, $this->password);
    }

    /**
     * 退出登录
     */
    public function logout(): bool
    {
        $this->auth_key = null;
        return $this->save();
    }

    /**
     * 更新用户认证秘钥
     */
    public function updateAuthKey(): void
    {
        $this->auth_key = substr(md5(base64_encode($this->username . '_' . time())), 5, 18);
    }

    /**
     * 判断当前管理员是否是超管
     * @return bool
     */
    public function isSuper(): bool
    {
        return $this->username === env('SUPER_ADMIN', 'administrator');
    }

    private static function getJwtInstance(): JwtHelper
    {
        return JwtHelper::instance([config('jwt.auth_admin')]);
    }

    /**
     * 获取登录用户
     * @param string $token
     * @return Admin
     * @throws \Exception
     */
    public static function getAuthAdmin(string $token): Admin
    {
        $jwtBody = self::getJwtInstance()->decode($token);
        if (!RespHelper::isSucceed($jwtBody)) {
            throw new BusinessException($jwtBody['code'], $jwtBody['message']);
        }
        $authKey = $jwtBody['data']['rows']['auth'] ?? '';
        /** @var self|null $authAdmin */
        if ($authAdmin = self::query()->where('auth_key', $authKey)->first()) {
            return $authAdmin;
        }
        throw new BusinessException(404, "登录信息已失效");
    }

    /**
     * 登录用户数据包
     * @param bool $needVoucher
     * @return array
     * @throws \Exception
     */
    public function package(bool $needVoucher = false): array
    {
        $isSuper = $this->isSuper();
        $menuList = (new MenuHandler)->getMenuByAdmin($this->id, $isSuper);
        $package = [
            'release' => IS_PROD,
            'username' => $this->username,
            'realname' => $this->realname,
            'create_at' => $this->created_at,
            'isSuper' => $isSuper,
            'authorization' => '',
            'menus' => $menuList
        ];
        if ($needVoucher) {
            $package['authorization'] = self::getJwtInstance()->encode(['auth' => $this->auth_key]);
        } else {
            unset($package['authorization']);
        }
        return $package;
    }

    /**
     * 用户修改密码
     * @param array $params
     * @return array
     */
    public function updatePassword(array $params): array
    {
        $curAdmin = self::getCurAdmin();
        if (!$curAdmin->validatePassword(@$params['old'])) {
            return RespHelper::fail('原密码输入错误');
        }
        if (empty($params['new'])) {
            return RespHelper::fail('新的密码不能为空');
        }
        $curAdmin->setPassword($params['new']);
        if ($curAdmin->save()) {
            return RespHelper::success();
        }
        return RespHelper::fail();
    }

    /**
     * 添加管理员
     * @param array $params
     * @return array
     */
    public function insertRow(array $params): array
    {
        if (empty($params['username']) || empty($params['realname']) || empty($params['password'])) {
            return RespHelper::fail('缺少必要参数！');
        }
        $username = trim($params['username']);
        $existAdmin = self::query()->where('username', $username)->first();
        if ($existAdmin) {
            return RespHelper::fail('账户名已存在');
        }
        $admin = new self();
        $admin->username = $username;
        $admin->realname = trim($params['realname']);
        $admin->state = self::STATE_NORMAL;
        $admin->setPassword($params['password']);
        $admin->created_at = date('Y-m-d H:i:s');
        Db::beginTransaction();
        try {
            $admin->save();
            //关联角色
            $roles = null;
            if (isset($params['roles'])) {
                $roles = $params['roles'];
            }
            $rolesData = [];
            if ($roles) {
                foreach ($roles as $v) {
                    $rolesData[] = ['role_id' => $v, 'uid' => $admin->id, "created_at" => date('Y-m-d H:i:s')];
                }
            }
            if ($rolesData)
                RoleAdmin::insert($rolesData);
            Db::commit();
        } catch (\Throwable $e) {
            Db::rollBack();
            return RespHelper::fail('操作失败' . $e->getMessage() . $e->getLine());
        }
        return RespHelper::success();

    }

    /**
     * 编辑管理员
     * @param array $params
     * @param int $id
     * @return array
     */
    public function updateRow(array $params, int $id): array
    {
        $curAdmin = self::getCurAdmin();
        if (empty($params['username']) || empty($params['realname'])) {
            return RespHelper::fail('缺少必要参数！');
        }
        $username = trim($params['username']);
        $existAdmin = self::query()->where([['username', $username], ['id', '<>', $id]])->first();
        if ($existAdmin) {
            return RespHelper::fail('账户名已存在');
        }
        /** @var self $admin */
        $admin = self::query()->find($id);
        if (!$admin) {
            return RespHelper::notfound();
        }
        if ($admin->id === $curAdmin->id) {
            return RespHelper::fail('您不能修改自己的账户');
        }
        $admin->username = $params['username'];
        $admin->realname = $params['realname'];
        if (!empty($params['password'])) {
            $password = trim($params['password']);
            // 更新密码时同时更新 登录状态
            $admin->setPassword($password);
            $admin->updateAuthKey();
        }
        $admin->updated_at = date('Y-m-d H:i:s');
        Db::beginTransaction();
        try {
            $today = date('Y-m-d H:i:s', time());
            $admin->save();
            $roles = null;
            if (isset($params['roles']))
                $roles = $params['roles'];

            $adminRoles = RoleAdmin::where('uid', $id)->pluck('role_id')->toArray();
            //新增的角色
            if ($roles) {
                $addRolesIds = array_diff($roles, $adminRoles);
                if ($addRolesIds) {
                    $insertData = [];
                    foreach ($addRolesIds as $v) {
                        $insertData[] = ['uid' => $id, 'role_id' => $v, 'created_at' => $today];
                    }
                    if ($insertData)
                        RoleAdmin::insert($insertData);
                }
            }

            //需要移除的角色
            if ($adminRoles) {
                $delRolesIds = array_diff($adminRoles, $roles);
                if ($delRolesIds) {
                    RoleAdmin::where('uid', $id)->whereIn('role_id', $delRolesIds)->delete();
                }
            }
            // 清除权限缓存
            $admin->clearRbacCache();
            Db::commit();
        } catch (\Throwable $e) {
            Db::rollBack();
            return RespHelper::fail();
        }
        return RespHelper::success();
    }

    /**
     * 删除管理员
     * @param int $id
     * @return array
     * @throws \Exception
     */
    public function deleteRow(int $id): array
    {
        $curAdmin = self::getCurAdmin();
        /** @var self $admin */
        $admin = self::query()->where('id', $id)->first();
        if (!$admin) {
            return RespHelper::notfound();
        }
        if (!$curAdmin->isSuper()) {
            return RespHelper::fail('无权对超级管理员进行修改');
        }
        if ($admin->id === $curAdmin->id) {
            return RespHelper::fail('您不能修改自己的账户');
        }
        if ($admin->delete()) {
            return RespHelper::success();
        }
        return RespHelper::fail();
    }

    /**
     * 更新状态
     * @param int $id
     * @param int $state
     * @return array
     */
    public function updateState(int $id, int $state): array
    {
        /** @var self $admin */
        $admin = self::find($id);
        if (!$admin) {
            return RespHelper::notfound();
        }
        /** @var self $curAdmin */
        $curAdmin = self::getCurAdmin();
        if ($admin->id === $curAdmin->id) {
            return RespHelper::fail('您不能修改自己的账户');
        }
        $admin->state = $state === 0 ? 0 : 1;
        if ($admin->save()) {
            return RespHelper::success();
        }
        return RespHelper::fail();
    }

}
